package edu.tfh.s2.ehkbot.gerete.aktoren.simulation;

import java.util.Date;
import java.util.Vector;

import edu.tfh.s2.ehkbot.daten.Einstellungen;
import edu.tfh.s2.ehkbot.daten.Zeitgeber;
import edu.tfh.s2.ehkbot.gerete.aktoren.MotorAktor.MotorAktorState;

/**
 * MotorAktorAktiviereStateSimulation implemenetiert den Zustand Simulation und Aktiviert für MotorAktorState.
 * 
 * @author s2zehn
 */
public class MotorAktorAktiviereStateSimulation implements MotorAktorState {

	/**
	 * MotorBefehl Loggt die Befehler die an den MotorAktor übergeben werden.
	 */
	public class MotorBefehl {
		private Date endDate; // wann solle er enden
		private double endGrad; // speichert die position nach den befehl, ist
		private double gradPerSec; // wie schnell soll er sich drehen
		// übergeben, endGrad ist gleich wunschGrad
		// wenn
		// nicht vorher stop gedrückt wurde
		private Date startDate; // wann wurde der befehl gestartet
		private double startGrad; // speichert die position vor den befehl
		// der startGrad für den nähsten befehl
		private double wunschGrad; // wie viel grad wurden in den befehl
	}

	private static final int MsPerSec = 1000;

	private Vector<MotorBefehl> befehl = new Vector<MotorBefehl>();
	private double maxSpeed;

	/**
	 * Konstruktor
	 */
	public MotorAktorAktiviereStateSimulation() {
		// init Motor Position
		MotorBefehl mb = new MotorBefehl();
		mb.startGrad = 0;
		mb.endGrad = 0;
		mb.startDate = Zeitgeber.getInstance().getCurrentDate();
		mb.endDate = Zeitgeber.getInstance().getCurrentDate();
		mb.gradPerSec = 0;
		mb.wunschGrad = 0;
		befehl.add(mb);

		maxSpeed = Einstellungen.getInstance().getDoublePropertie("MotorAktorMaxGradPerSec");
	}

	/**
	 * @see edu.tfh.s2.ehkbot.gerete.aktoren.MotorAktor.MotorAktorState#drehe(double, double)
	 */
	@Override
	public void drehe(double grad, double gradPerSec) {
		stope();
		Date now = Zeitgeber.getInstance().getCurrentDate();
		MotorBefehl mb = new MotorBefehl();
		mb.startGrad = befehl.lastElement().endGrad;
		mb.gradPerSec = gradPerSec;
		mb.wunschGrad = grad;
		mb.startDate = now;
		mb.endGrad = mb.startGrad + mb.wunschGrad;
		mb.endDate = new Date(now.getTime() + (long) (MsPerSec * grad / gradPerSec));

		befehl.add(mb);
	}

	/**
	 * @see edu.tfh.s2.ehkbot.gerete.aktoren.MotorAktor.MotorAktorState#getDrehung()
	 */
	@Override
	public double getDrehung() {
		Date to_untill = Zeitgeber.getInstance().getCurrentDate();
		if (befehl.lastElement().endDate.before(to_untill)) {
			return befehl.lastElement().endGrad;
		}

		double secSpend = (to_untill.getTime() - befehl.lastElement().startDate.getTime()) / MsPerSec;
		double grad = secSpend * befehl.lastElement().gradPerSec; // wie viel
		// grad
		// wurden
		// gemacht
		return befehl.lastElement().startGrad + grad;
	}

	/**
	 * @see edu.tfh.s2.ehkbot.gerete.aktoren.MotorAktor.MotorAktorState#getGradPerSec()
	 */
	@Override
	public double getGradPerSec() {
		return befehl.lastElement().gradPerSec;
	}

	@Override
	public double getMaxSpeed() {
		return maxSpeed;
	}

	/**
	 * Liefert die Liste der MotorBefehle.
	 * 
	 * @return Die liste der MotorBefehle
	 */
	public Vector<MotorBefehl> getMotorBefehle() {
		return befehl;
	}

	/**
	 * @see edu.tfh.s2.ehkbot.gerete.aktoren.MotorAktor.MotorAktorState#istAktiviert()
	 */
	@Override
	public boolean istAktiviert() {
		return true;
	}

	/**
	 * @see edu.tfh.s2.ehkbot.gerete.aktoren.MotorAktor.MotorAktorState#stope()
	 */
	@Override
	public void stope() {
		Date now = Zeitgeber.getInstance().getCurrentDate();
		if (befehl.lastElement().endDate.after(now)) { // der letzte befehl is
			// noch nicht
			// abgearbeitet
			double secSpend = (now.getTime() - befehl.lastElement().startDate.getTime()) / MsPerSec;
			double grad = secSpend * befehl.lastElement().gradPerSec; // wie
			// viel
			// grad
			// wurden
			// gemacht
			befehl.lastElement().endDate = now;
			befehl.lastElement().endGrad = befehl.lastElement().startGrad + grad;
		}
	}

	/**
	 * @see edu.tfh.s2.ehkbot.gerete.aktoren.MotorAktor.MotorAktorState#waitUntilDone()
	 */
	@Override
	public void waitUntilDone() {
		double epslilon = Einstellungen.getInstance().getDoublePropertie("Epsilon");
		while (Math.abs(getDrehung() - befehl.lastElement().endGrad) > epslilon) {
			Zeitgeber.getInstance().sleep(10);
		}

	}
}
